package com.kermel.common.action;

import java.util.Calendar;

import android.test.AndroidTestCase;

import com.kermel.andromeda.action.AlarmAction;
import com.kermel.andromeda.data.Alarm;
import com.kermel.andromeda.data.AlarmTest;
import com.kermel.andromeda.engine.mock.MockFutureAction;
import com.kermel.common.util.DateTimeUtils;

public class FutureActionSchedulerTest extends AndroidTestCase {
    public static final long UNKNOWN_TRIGGER_TIME = -1;
    public static final String WAIT_FOR_TRIGGER_TO_FIRE_TIMER_NAME = "WaitForTriggerToFireTimer";
    public static final long MILLISECONDS_PER_SECOND = 1000;
    public static final int DEFAULT_TRIGGER_TIME_SECONDS = 5;
    public static final int IMMEDIATELY = 0;
    
    private FutureActionScheduler scheduler;
    private MockFutureAction actionFixture;
    
    protected void setUp() throws Exception {
        super.setUp();
        
        scheduler = new FutureActionScheduler();
        actionFixture = new MockFutureAction();
    }

    protected void tearDown() throws Exception {
        scheduler = null;
        actionFixture = null;
        
        super.tearDown();
    }
    
    private long calculateTriggerTime(int howManySecondsFromNow) {
        long triggerTime = UNKNOWN_TRIGGER_TIME;
        
        System.out.println(String.format("howManySecondsFromNow: %d", howManySecondsFromNow));
        
        Calendar now = Calendar.getInstance();
        System.out.println(String.format("        now: %s", DateTimeUtils.timeInMillisecondsToDate(now.getTimeInMillis())));
        
        now.add(Calendar.SECOND, howManySecondsFromNow);
        triggerTime = now.getTimeInMillis();
        System.out.println(String.format("triggerTime: %s", DateTimeUtils.timeInMillisecondsToDate(triggerTime)));
        
        return triggerTime;
    }
    
    public void testThatWhenTheActionIsNullTheSchedulerDoesNotThrowAnException() {
        boolean exceptionCaught = false;
        boolean result = false;
        
        result = scheduler.scheduleFutureAction(null, 0);
        
        assertFalse(exceptionCaught);
        assertFalse(result);
    }
    
    public void testThatWhenTheActionIsScheduledItIsMarkedAsBeingScheduled() {
        boolean result = false;
        long triggerTime = calculateTriggerTime(0);
        
        result = scheduler.scheduleFutureAction(actionFixture, triggerTime);
        assertTrue(actionFixture.isScheduled());
        assertTrue(result);
    }
    
    public void testThatWhenTheActionIsNullScheduleAlarmHandlesItGracefully() {
        boolean exceptionCaught = false;
        
        try {
            boolean result = false;
            AlarmAction alarmAction = null;
            
            result = scheduler.scheduleAlarm(alarmAction);
            assertFalse(result);
            
        } catch (Exception e) {
            exceptionCaught = true;
        }
        
        assertFalse(exceptionCaught);
    }
    
    public void testThatWhenAlarmIsNullAlarmActionDoesNotScheduleAlarm() {
        
        boolean exceptionCaught = false;
        
        try {
            Alarm alarm = null;
            AlarmAction alarmAction = new AlarmAction(alarm, getContext());
            
            boolean result = false;
            result = scheduler.scheduleAlarm(alarmAction);
            assertFalse(result);
            
        } catch (Exception e) {
            exceptionCaught = true;
        }
        
        assertFalse(exceptionCaught);
    }
    
    public void testScheduleAlarmSuccess() {
        boolean result = false;
        
        Alarm alarm = AlarmTest.createAlarmFixture();
        AlarmAction alarmAction = new AlarmAction(alarm, getContext());
        
        // Disable the alarm to prevent the switch to TriggeredAlarmActivity
        alarm.enabled = false;
        
        result = scheduler.scheduleAlarm(alarmAction);
        assertTrue(result);
    }
    
    public void testThatCancelAlarmIgnoresAnAlarmActionThatIsNull() {
        AlarmAction alarmAction = null; 

        boolean result = scheduler.cancelAlarm(alarmAction);
        assertFalse(result);
    }
    
}
